#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
玩客云 SSD1315 OLED 系统信息显示 (I2C驱动版, 动态对齐, CPU/Temp 3秒刷新)
功能：
1.  显示主机名 (可滚动) 和 CPU 占用率 (右上角 | x% 或 |xx%)。
2.  显示 MAC 地址 (左侧可滚动, 去掉冒号) 和 CPU 温度 (右侧 |xC 或 |xxC，与CPU%右对齐)。
3.  显示 IP 地址 (居中，可滚动)。
4.  显示日期和时间 (左下角和右下角)。
5.  实现文本滚动效果。
针对使用 oled_driver_i2c.py 模块进行了适配，适用于 128x64 OLED 屏幕。
- CPU 占用率和温度显示根据数值动态调整对齐 (个位数时前面加空格)。
- CPU 占用率和温度更新频率降低为 3 秒一次。
"""

# --- 导入必要的库 ---
import time
import os
import glob

# --- 导入硬件/系统信息库 ---
PSUTIL_AVAILABLE = False
NETIFACES_AVAILABLE = False
try:
    import psutil
    PSUTIL_AVAILABLE = True
except ImportError:
    pass # print("警告: 未安装 psutil 库，部分系统信息 (CPU, 温度, MAC) 将无法获取。")
    # print("      可通过 'pip install psutil' 安装。")

try:
    import netifaces
    NETIFACES_AVAILABLE = True
except ImportError:
    pass # print("警告: 未安装 netifaces 库，IP 地址将无法获取。")
    # print("      可通过 'pip install netifaces' 安装。")

# --- 导入自定义模块 ---
try:
    import oled_driver_i2c as oled_driver  # 导入针对玩客云 I2C 的 OLED 驱动模块
except ImportError:
    raise ImportError("错误: 找不到 oled_driver_i2c 模块。请确保 oled_driver_i2c.py 在同一目录下。")

try:
    import font_data  # 导入字体数据模块
except ImportError:
    raise ImportError("错误: 找不到 font_data 模块。请确保 font_data.py 在同一目录下。")


# --- 全局常量 ---
# --- 修复 1: 将 NAME_FILE_PATH 改为当前目录下的 name.txt ---
NAME_FILE_PATH = "./name.txt"  # 存放主机名的文件路径 (当前目录)

# --- 文本滚动辅助函数 ---
class TextScroller:
    """用于管理文本滚动状态的类"""
    def __init__(self, text, width_chars=16):
        self.text = text
        self.width_chars = width_chars
        self.offset = 0
        self.text_len = len(self.text)
        self.needs_scrolling = self.text_len > self.width_chars

    def get_display_text(self):
        """获取当前应显示的文本片段"""
        if not self.needs_scrolling:
            return self.text
        display_text = self.text + " "
        display_len = len(display_text)
        start_index = self.offset % display_len
        end_index = start_index + self.width_chars

        if end_index <= display_len:
            return display_text[start_index:end_index]
        else:
            part1 = display_text[start_index:]
            part2 = display_text[:end_index - display_len]
            return part1 + part2

    def update(self):
        """更新滚动偏移量"""
        if self.needs_scrolling:
            self.offset += 1

# --- 系统信息获取函数 ---

def clean_mac_address(mac_str):
    """去除 MAC 地址中的冒号和横线"""
    if not mac_str:
        return "000000000000"
    cleaned = mac_str.replace(':', '').replace('-', '').upper()
    # 确保长度为 12
    if len(cleaned) == 12:
        return cleaned
    else:
        # pass # print(f"警告: 清理后的 MAC 地址 '{cleaned}' 长度不是 12，使用默认值。")
        return "000000000000"

def get_system_info():
    """获取并格式化系统信息 (返回原始值或默认值)"""
    info = {}

    # --- 获取主机名 (从文件 name.txt) ---
    try:
        # --- 修复 1: 使用当前目录下的 name.txt ---
        with open(NAME_FILE_PATH, 'r', encoding='utf-8') as f:
            hostname = f.read().strip()
        info['hostname'] = hostname if hostname else "NoName"
    except FileNotFoundError:
        # pass # print(f"警告: 未找到文件 '{NAME_FILE_PATH}'，使用默认名称 'NoName'")
        info['hostname'] = "NoName"
    except Exception as e:
        # pass # print(f"读取主机名文件 '{NAME_FILE_PATH}' 出错: {e}")
        info['hostname'] = "Error"

    # --- 获取 CPU 占用率 (返回整数) ---
    try:
        cpu_percent = psutil.cpu_percent(interval=0.1) if PSUTIL_AVAILABLE else 0.0
        # 确保不超过 99，并格式化为整数
        cpu_percent_int = int(min(cpu_percent, 99.0))
        info['cpu_percent'] = cpu_percent_int
    except Exception as e:
        # pass # print(f"获取 CPU 占用率失败: {e}")
        info['cpu_percent'] = -1 # 使用 -1 表示错误

    # --- 获取 CPU 温度 (返回整数) ---
    info['cpu_temp'] = -1 # 使用 -1 表示错误或未获取
    temp_found = False # 标志位，用于判断是否找到温度
    if PSUTIL_AVAILABLE:
        try:
            # --- 优化: 尝试多种方式获取温度 ---
            temps = psutil.sensors_temperatures()
            if temps:
                # --- 方法 1: 查找 CPU 相关的传感器 (常见名称) ---
                # pass # print(f"调试: psutil.sensors_temperatures() 返回: {temps}")
                for name, entries in temps.items():
                    # 尝试匹配常见的 CPU 传感器名称
                    if any(keyword in name.lower() for keyword in ['coretemp', 'cpu', 'k10temp', 'acpi', 'thermal']):
                        # pass # print(f"调试: 尝试从传感器 '{name}' 获取温度...")
                        for entry in entries:
                            if entry.current is not None:
                                temp_value = int(entry.current)
                                # pass # print(f"调试: 从传感器 '{name}' 成功获取温度 {temp_value}°C")
                                info['cpu_temp'] = temp_value
                                temp_found = True
                                break # 找到一个有效的就跳出
                    if temp_found:
                        break # 找到就跳出外层循环

            # --- 方法 2: 如果方法 1 没找到，尝试读取 thermal_zone 文件 (Linux) ---
            if not temp_found:
                # pass # print("调试: psutil 未找到温度，尝试读取 /sys/class/thermal/thermal_zone*/temp...")
                thermal_zones = glob.glob('/sys/class/thermal/thermal_zone*')
                for zone_path in thermal_zones:
                    try:
                        with open(os.path.join(zone_path, 'type'), 'r') as f:
                            zone_type = f.read().strip().lower()
                        # 尝试匹配 CPU 或 acpi 相关的 zone
                        if 'cpu' in zone_type or 'acpi' in zone_type or 'x86' in zone_type:
                             with open(os.path.join(zone_path, 'temp'), 'r') as f:
                                 temp_milli_c = int(f.read().strip())
                                 temp_c = temp_milli_c / 1000.0
                                 temp_value = int(temp_c)
                                 # pass # print(f"调试: 从 thermal_zone '{zone_type}' ({zone_path}) 成功获取温度 {temp_value}°C")
                                 info['cpu_temp'] = temp_value
                                 temp_found = True
                                 break # 找到一个有效的就跳出
                    except (FileNotFoundError, ValueError, PermissionError) as e:
                         # pass # print(f"调试: 读取 thermal_zone '{zone_path}' 失败: {e}")
                         continue # 继续尝试下一个 zone

            # --- 方法 3: 尝试读取最常见的 thermal_zone0 ---
            if not temp_found:
                # pass # print("调试: 尝试读取 /sys/class/thermal/thermal_zone0/temp ...")
                try:
                    with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
                        temp_milli_c = int(f.read().strip())
                        temp_c = temp_milli_c / 1000.0
                        temp_value = int(temp_c)
                        # pass # print(f"调试: 从 /sys/class/thermal/thermal_zone0/temp 成功获取温度 {temp_value}°C")
                        info['cpu_temp'] = temp_value
                        temp_found = True
                except (FileNotFoundError, ValueError, PermissionError) as e:
                     # pass # print(f"调试: 读取 /sys/class/thermal/thermal_zone0/temp 失败: {e}")
                     pass

        except Exception as e:
            # pass # print(f"获取 CPU 温度失败 (psutil 或文件读取): {e}")
            # import traceback
            # traceback.print_exc() # 打印详细错误堆栈
            pass # 静默处理

    # --- 获取 IP 地址 ---
    info['ip'] = "0.0.0.0"
    if NETIFACES_AVAILABLE:
        try:
            for interface in netifaces.interfaces():
                if interface == 'lo':
                    continue
                addresses = netifaces.ifaddresses(interface)
                if netifaces.AF_INET in addresses:
                    for addr_info in addresses[netifaces.AF_INET]:
                        ip = addr_info['addr']
                        if ip and not ip.startswith("127."):
                            info['ip'] = ip
                            break
                if info['ip'] != "0.0.0.0":
                    break
        except Exception as e:
            # pass # print(f"获取 IP 地址失败: {e}")
            pass

    # --- 获取 MAC 地址 (使用第一个非回环接口的 MAC) ---
    info['mac'] = "000000000000" # 默认值，无冒号
    mac_found = False
    if PSUTIL_AVAILABLE:
        try:
            # 遍历网络接口卡
            nics = psutil.net_if_addrs()
            for nic_name, snic_list in nics.items():
                 # 跳过回环接口
                if nic_name == 'lo':
                     continue
                for snic in snic_list:
                    # 查找 MAC 地址 (AF_LINK 在某些系统上可能不同，AF_PACKET 更通用)
                    # 但 psutil 中通常用 family == 17 (AF_PACKET) 来表示 MAC 地址
                    if snic.family == 17: # AF_PACKET
                        raw_mac = snic.address
                        # --- 强化: 使用独立函数去除 MAC 地址中的冒号 ---
                        info['mac'] = clean_mac_address(raw_mac)
                        # pass # print(f"调试: 通过 psutil 获取到 MAC 地址 '{raw_mac}' 并清理为 '{info['mac']}'")
                        mac_found = True
                        break
                if mac_found:
                    break
        except Exception as e:
             # pass # print(f"通过 psutil 获取 MAC 地址失败: {e}")
             # import traceback
             # traceback.print_exc() # 打印详细错误堆栈
             pass

    # --- 备用方法: 如果 psutil 获取 MAC 失败，尝试读取系统文件 ---
    if not mac_found:
        # pass # print("调试: psutil 未获取到 MAC，尝试读取 /sys/class/net/<interface>/address ...")
        try:
            # 获取网络接口列表
            net_interfaces = os.listdir('/sys/class/net/')
            for interface in net_interfaces:
                if interface == 'lo':
                    continue
                addr_path = f'/sys/class/net/{interface}/address'
                if os.path.exists(addr_path):
                    with open(addr_path, 'r') as f:
                        raw_mac = f.read().strip()
                    if raw_mac and raw_mac != '00:00:00:00:00:00':
                        # --- 强化: 使用独立函数去除 MAC 地址中的冒号 ---
                        info['mac'] = clean_mac_address(raw_mac)
                        # pass # print(f"调试: 通过系统文件 '{addr_path}' 获取到 MAC 地址 '{raw_mac}' 并清理为 '{info['mac']}'")
                        mac_found = True
                        break
        except Exception as e:
             # pass # print(f"通过系统文件获取 MAC 地址失败: {e}")
             # import traceback
             # traceback.print_exc() # 打印详细错误堆栈
             pass

    if not mac_found:
        # pass # print("警告: 无法获取有效的 MAC 地址，使用默认值。")
        pass


    # --- 获取当前日期和时间 ---
    now = time.localtime()
    info['date'] = time.strftime("%Y-%m-%d", now)
    # --- 修复: 时间格式改为不包含秒 ---
    info['time'] = time.strftime("%H:%M", now) # <<<<<<<<< 修改这里，去掉 :%S

    return info


# --- 主函数 ---
def main():
    """主程序循环"""
    # pass # print("正在初始化 OLED 显示...")

    # --- 初始化 GPIO 和 OLED ---
    try:
        oled_driver.init_gpio() # 初始化 GPIO
        oled_driver.init()      # 初始化 OLED
        oled_driver.clear()     # 清屏
    except Exception as e:
        # pass # print(f"OLED 初始化失败: {e}")
        return

    # --- 初始化变量 ---
    prev_hostname = ""
    prev_cpu_percent = -2 # 初始值与任何有效值或错误值都不同
    prev_mac = ""
    prev_cpu_temp = -2    # 初始值与任何有效值或错误值都不同
    prev_ip = ""
    prev_date = ""
    prev_time = ""

    # --- 滚动相关 ---
    scroll_step_interval = 0.3  # 每 0.3 秒滚动一步
    last_scroll_time = time.time()

    # --- 假设字体大小为 16x16 像素 ---
    CHAR_WIDTH = 8
    CHAR_HEIGHT = 16

    # --- 计算固定区域 X 坐标 (右对齐) ---
    # 最大显示宽度 "|99%" 或 "|99C" 为 4 个字符
    FIXED_AREA_WIDTH_CHARS = 4
    FIXED_AREA_WIDTH_PX = FIXED_AREA_WIDTH_CHARS * CHAR_WIDTH # 4 * 8 = 32
    FIXED_AREA_START_X = oled_driver.OLED_WIDTH - FIXED_AREA_WIDTH_PX # 128 - 32 = 96

    # --- 第一行 (CPU%) ---
    cpu_percent_pipe_x = FIXED_AREA_START_X # 96

    # --- 第二行 (MAC + Temp) ---
    # "|xxC" 的坐标与第一行完全一致
    cpu_temp_pipe_x = FIXED_AREA_START_X # 96

    # MAC 地址滚动区域 (从 0 到 FIXED_AREA_START_X - 1)
    mac_scroll_area_width_px = FIXED_AREA_START_X # 96
    mac_scroll_area_chars = mac_scroll_area_width_px // CHAR_WIDTH # 96 // 8 = 12

    # --- 第三行 (IP) ---
    # 居中处理，在更新时计算

    # --- 第四行 (Date/Time) ---
    # 左下角和右下角，在更新时计算

    # --- 初始化滚动器 ---
    hostname_scroller = TextScroller("", oled_driver.OLED_WIDTH // CHAR_WIDTH)
    mac_scroller = TextScroller("", mac_scroll_area_chars)
    ip_scroller = TextScroller("", oled_driver.OLED_WIDTH // CHAR_WIDTH)

    # --- 更新间隔 ---
    fast_update_interval = 1.0  # 快速更新 (Hostname, IP, Date, Time) 每秒
    # --- 修复: 将 CPU 和温度的更新频率改为 3 秒 ---
    slow_update_interval = 3.0  # 慢速更新 (CPU%, Temp) 每3秒
    last_fast_update_time = 0
    last_slow_update_time = 0 # 新增：用于跟踪慢速更新

    # pass # print("开始显示系统信息...")

    try:
        while True:
            current_time = time.time()

            # --- 定期更新快速变化的系统信息 (Hostname, IP, Date, Time) ---
            if current_time - last_fast_update_time >= fast_update_interval:
                sys_info = get_system_info()
                new_hostname = sys_info['hostname']
                # new_cpu_percent = sys_info['cpu_percent'] # 移动到慢速更新
                new_mac = sys_info['mac'] # 已经是清理后的 MAC
                # new_cpu_temp = sys_info['cpu_temp'] # 移动到慢速更新
                new_ip = sys_info['ip']
                new_date = sys_info['date']
                new_time = sys_info['time']

                # --- 检查并更新第一行 (Hostname) ---
                if new_hostname != prev_hostname:
                    hostname_scroller.text = new_hostname
                    hostname_scroller.text_len = len(hostname_scroller.text)
                    hostname_scroller.width_chars = oled_driver.OLED_WIDTH // CHAR_WIDTH
                    hostname_scroller.needs_scrolling = hostname_scroller.text_len > hostname_scroller.width_chars
                    hostname_scroller.offset = 0 # 重置滚动
                    prev_hostname = new_hostname

                    # 清除第一行 (Page 0-1)
                    for x in range(oled_driver.OLED_WIDTH):
                        oled_driver.OLED_GRAM[x, 0] = 0
                        oled_driver.OLED_GRAM[x, 1] = 0

                    # 绘制 Hostname (初始片段)
                    display_hostname = hostname_scroller.get_display_text()
                    oled_driver.show_string(0, 0, display_hostname, font_data, size=16, mode=1)

                    # 注意：CPU% 在慢速更新中绘制，这里不处理

                    # 刷新第一行
                    oled_driver.refresh_gram()

                # --- 检查并更新第二行 (MAC) ---
                if new_mac != prev_mac:
                    # --- 强化: 确保使用的 MAC 是清理后的 ---
                    mac_scroller.text = new_mac # new_mac 已经是 12 位无冒号的字符串
                    # pass # print(f"调试: 更新 MAC 滚动器文本为 '{new_mac}'")
                    mac_scroller.text_len = len(mac_scroller.text)
                    mac_scroller.width_chars = mac_scroll_area_chars # 12 个字符
                    mac_scroller.needs_scrolling = mac_scroller.text_len > mac_scroller.width_chars
                    mac_scroller.offset = 0 # 重置滚动
                    prev_mac = new_mac

                    # 清除第二行 (Page 2-3)
                    for x in range(oled_driver.OLED_WIDTH):
                        oled_driver.OLED_GRAM[x, 2] = 0
                        oled_driver.OLED_GRAM[x, 3] = 0

                    # 绘制 MAC (初始片段)
                    display_mac = mac_scroller.get_display_text()
                    # pass # print(f"调试: 绘制 MAC 初始片段 '{display_mac}'")
                    # --- 强化: MAC 从 x=0 开始绘制 ---
                    oled_driver.show_string(0, 16, display_mac, font_data, size=16, mode=1) # y=16 是第 2 页 (page 2) 的起始像素

                    # 注意：CPU 温度在慢速更新中绘制，这里不处理

                    # 刷新第二行
                    oled_driver.refresh_gram()

                # --- 检查并更新第三行 (IP, 居中) ---
                if new_ip != prev_ip:
                    ip_scroller.text = new_ip
                    ip_scroller.text_len = len(ip_scroller.text)
                    ip_scroller.width_chars = oled_driver.OLED_WIDTH // CHAR_WIDTH # 整行宽度
                    ip_scroller.needs_scrolling = ip_scroller.text_len > ip_scroller.width_chars
                    ip_scroller.offset = 0 # 重置滚动

                    # 计算居中起始 X 坐标
                    ip_text_width_px = len(new_ip) * CHAR_WIDTH
                    ip_start_x = (oled_driver.OLED_WIDTH - ip_text_width_px) // 2
                    if ip_start_x < 0: ip_start_x = 0

                    # 清除第三行 (Page 4-5)
                    for x in range(oled_driver.OLED_WIDTH):
                        oled_driver.OLED_GRAM[x, 4] = 0
                        oled_driver.OLED_GRAM[x, 5] = 0

                    # 绘制 IP (初始片段, 居中)
                    display_ip = ip_scroller.get_display_text()
                    # 重新计算居中起始点 (滚动后)
                    display_ip_width_px = len(display_ip) * CHAR_WIDTH
                    centered_start_x = (oled_driver.OLED_WIDTH - display_ip_width_px) // 2
                    if centered_start_x < 0: centered_start_x = 0
                    oled_driver.show_string(centered_start_x, 32, display_ip, font_data, size=16, mode=1) # y=32 是第 4 页 (page 4) 的起始像素

                    # 刷新第三行
                    oled_driver.refresh_gram()
                    prev_ip = new_ip

                # --- 检查并更新第四行 (Date, Time) ---
                date_changed = new_date != prev_date
                time_changed = new_time != prev_time

                if date_changed or time_changed:
                   # 清除第四行 (Page 6-7)
                    for x in range(oled_driver.OLED_WIDTH):
                        oled_driver.OLED_GRAM[x, 6] = 0
                        oled_driver.OLED_GRAM[x, 7] = 0

                    # 绘制日期 (左下角)
                    oled_driver.show_string(0, 48, new_date, font_data, size=16, mode=1) # y=48 是第 6 页 (page 6) 的起始像素

                    # 绘制时间 (右下角)
                    time_text_width_new = len(new_time) * CHAR_WIDTH
                    time_x = oled_driver.OLED_WIDTH - time_text_width_new
                    if time_x < 0: time_x = 0
                    oled_driver.show_string(time_x, 48, new_time, font_data, size=16, mode=1) # y=48

                    # 刷新第四行
                    oled_driver.refresh_gram()

                    if date_changed:
                         prev_date = new_date
                    if time_changed:
                         prev_time = new_time

                last_fast_update_time = current_time

            # --- 定期更新慢速变化的系统信息 (CPU%, Temp) ---
            # --- 修复: 每3秒更新一次 CPU 占用率和温度 ---
            if current_time - last_slow_update_time >= slow_update_interval:
                sys_info_slow = get_system_info() # 重新获取需要慢速更新的信息
                # --- 修复: 直接获取整数值 ---
                new_cpu_percent = sys_info_slow['cpu_percent']
                new_cpu_temp = sys_info_slow['cpu_temp']

                cpu_percent_changed = new_cpu_percent != prev_cpu_percent
                cpu_temp_changed = new_cpu_temp != prev_cpu_temp

                # --- 检查并更新第一行 (CPU%) ---
                if cpu_percent_changed:
                    # 清除第一行右侧固定区域 (Page 0-1)
                    for x in range(FIXED_AREA_START_X, oled_driver.OLED_WIDTH):
                        oled_driver.OLED_GRAM[x, 0] = 0
                        oled_driver.OLED_GRAM[x, 1] = 0

                    # --- 修复: 动态显示 CPU% (| x% 或 |xx%) ---
                    oled_driver.show_char(cpu_percent_pipe_x, 0, '|', font_data, size=16, mode=1) # 显示 |
                    if new_cpu_percent == -1: # 错误状态
                        oled_driver.show_string(cpu_percent_pipe_x + CHAR_WIDTH, 0, " --%", font_data, size=16, mode=1)
                    elif 0 <= new_cpu_percent <= 9: # 个位数 (0-9)
                         # 显示为 "| x%" (竖线后一个空格)
                         formatted_cpu = f" {new_cpu_percent}%"
                         oled_driver.show_string(cpu_percent_pipe_x + CHAR_WIDTH, 0, formatted_cpu, font_data, size=16, mode=1)
                    elif 10 <= new_cpu_percent <= 99: # 两位数 (10-99)
                         # 显示为 "|xx%" (竖线后无空格)
                         formatted_cpu = f"{new_cpu_percent}%"
                         oled_driver.show_string(cpu_percent_pipe_x + CHAR_WIDTH, 0, formatted_cpu, font_data, size=16, mode=1)
                    else: # 不在预期范围或错误
                         oled_driver.show_string(cpu_percent_pipe_x + CHAR_WIDTH, 0, " ??%", font_data, size=16, mode=1)


                    # 刷新第一行
                    oled_driver.refresh_gram()
                    prev_cpu_percent = new_cpu_percent # 更新 CPU% 状态

                # --- 检查并更新第二行 (CPU Temp) ---
                if cpu_temp_changed:
                    # 清除第二行右侧固定区域 (Page 2-3)
                    for x in range(FIXED_AREA_START_X, oled_driver.OLED_WIDTH):
                        oled_driver.OLED_GRAM[x, 2] = 0
                        oled_driver.OLED_GRAM[x, 3] = 0

                    # --- 强化: 动态显示 CPU 温度 (| xC 或 |xxC) ---
                    oled_driver.show_char(cpu_temp_pipe_x, 16, '|', font_data, size=16, mode=1) # 显示 |
                    if new_cpu_temp == -1: # 错误状态
                        oled_driver.show_string(cpu_temp_pipe_x + CHAR_WIDTH, 16, " --C", font_data, size=16, mode=1)
                    elif 0 <= new_cpu_temp <= 9: # 个位数 (0-9)
                         # 显示为 "| xC" (竖线后一个空格)
                         formatted_temp = f" {new_cpu_temp}C"
                         oled_driver.show_string(cpu_temp_pipe_x + CHAR_WIDTH, 16, formatted_temp, font_data, size=16, mode=1)
                    elif 10 <= new_cpu_temp <= 99: # 两位数 (10-99)
                         # 显示为 "|xxC" (竖线后无空格)
                         formatted_temp = f"{new_cpu_temp}C"
                         oled_driver.show_string(cpu_temp_pipe_x + CHAR_WIDTH, 16, formatted_temp, font_data, size=16, mode=1)
                    else: # 不在预期范围或错误 (-2 或其他)
                         oled_driver.show_string(cpu_temp_pipe_x + CHAR_WIDTH, 16, " ??C", font_data, size=16, mode=1)

                    # 刷新第二行
                    oled_driver.refresh_gram()
                    prev_cpu_temp = new_cpu_temp # 更新 CPU Temp 状态

                last_slow_update_time = current_time # 更新慢速更新时间戳

            # --- 更新滚动偏移 (周期性) ---
            if current_time - last_scroll_time >= scroll_step_interval:
                scroll_updated = False
                # 更新 Hostname 滚动 (第一行)
                if hostname_scroller.needs_scrolling:
                    hostname_scroller.update()
                    # 清除 Hostname 可滚动区域 (整行)
                    clear_start_x = 0
                    clear_end_x = oled_driver.OLED_WIDTH - 1
                    for x in range(clear_start_x, clear_end_x + 1):
                        oled_driver.OLED_GRAM[x, 0] = 0
                        oled_driver.OLED_GRAM[x, 1] = 0
                    # 绘制并刷新 Hostname 区域
                    display_hostname = hostname_scroller.get_display_text()
                    oled_driver.show_string(0, 0, display_hostname, font_data, size=16, mode=1)
                    # 刷新整个 GRAM 或部分区域 (简单处理)
                    oled_driver.refresh_gram()
                    scroll_updated = True

                # 更新 MAC 滚动 (第二行)
                if mac_scroller.needs_scrolling:
                    mac_scroller.update()
                    # 清除 MAC 可滚动区域 (左侧部分)
                    clear_start_x = 0
                    clear_end_x = mac_scroll_area_width_px - 1
                    if clear_end_x < clear_start_x: clear_end_x = clear_start_x
                    for x in range(clear_start_x, clear_end_x + 1):
                        oled_driver.OLED_GRAM[x, 2] = 0
                        oled_driver.OLED_GRAM[x, 3] = 0
                    # 绘制并刷新 MAC 区域
                    display_mac = mac_scroller.get_display_text()
                    # pass # print(f"调试: 滚动更新 MAC 显示片段 '{display_mac}'") # 添加调试日志
                    oled_driver.show_string(0, 16, display_mac, font_data, size=16, mode=1) # y=16
                    # 刷新整个 GRAM 或部分区域 (简单处理)
                    oled_driver.refresh_gram()
                    scroll_updated = True

                # 更新 IP 滚动 (第三行)
                if ip_scroller.needs_scrolling:
                    ip_scroller.update()
                    # 清除第三行
                    clear_start_x = 0
                    clear_end_x = oled_driver.OLED_WIDTH - 1
                    for x in range(clear_start_x, clear_end_x + 1):
                        oled_driver.OLED_GRAM[x, 4] = 0
                        oled_driver.OLED_GRAM[x, 5] = 0
                    # 绘制并刷新 IP 行 (居中)
                    display_ip = ip_scroller.get_display_text()
                    display_ip_width_px = len(display_ip) * CHAR_WIDTH
                    centered_start_x = (oled_driver.OLED_WIDTH - display_ip_width_px) // 2
                    if centered_start_x < 0: centered_start_x = 0
                    oled_driver.show_string(centered_start_x, 32, display_ip, font_data, size=16, mode=1) # y=32
                    # 刷新整个 GRAM 或部分区域 (简单处理)
                    oled_driver.refresh_gram()
                    scroll_updated = True

                if scroll_updated:
                    last_scroll_time = current_time

            # --- 简单的循环延迟 ---
            time.sleep(0.05) # 20 FPS

    except KeyboardInterrupt:
        # pass # print("\n程序被用户中断")
        pass
    except Exception as e:
        # pass # print(f"发生错误: {e}")
        # import traceback
        # traceback.print_exc()
        pass
    finally:
        # pass # print("正在清理资源...")
        oled_driver.clear()
        oled_driver.deinit_gpio() # 清理 GPIO 资源
        # pass # print("程序结束")


if __name__ == "__main__":
    main()




